﻿namespace System.ServiceModel.DomainServices.Client
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Globalization;
    using System.Linq;

    public abstract class DomainClient
    {
        private ReadOnlyCollection<Type> _entityTypes;

        protected DomainClient()
        {
        }

        public IAsyncResult BeginInvoke(InvokeArgs invokeArgs, AsyncCallback callback, object userState)
        {
            if (invokeArgs == null)
            {
                throw new ArgumentNullException("invokeArgs");
            }
            if (callback == null)
            {
                throw new ArgumentNullException("callback");
            }
            DomainClientAsyncResult result = DomainClientAsyncResult.CreateInvokeResult(this, invokeArgs, callback, userState);
            result.InnerAsyncResult = this.BeginInvokeCore(invokeArgs, delegate (IAsyncResult result) {
                DomainClientAsyncResult asyncState = (DomainClientAsyncResult) result.AsyncState;
                asyncState.InnerAsyncResult = result;
                asyncState.Complete();
            }, result);
            return result;
        }

        protected virtual IAsyncResult BeginInvokeCore(InvokeArgs invokeArgs, AsyncCallback callback, object userState)
        {
            throw new NotSupportedException();
        }

        public IAsyncResult BeginQuery(EntityQuery query, AsyncCallback callback, object userState)
        {
            if (query == null)
            {
                throw new ArgumentNullException("query");
            }
            if (callback == null)
            {
                throw new ArgumentNullException("callback");
            }
            DomainClientAsyncResult result = DomainClientAsyncResult.CreateQueryResult(this, callback, userState);
            result.InnerAsyncResult = this.BeginQueryCore(query, delegate (IAsyncResult result) {
                DomainClientAsyncResult asyncState = (DomainClientAsyncResult) result.AsyncState;
                asyncState.InnerAsyncResult = result;
                asyncState.Complete();
            }, result);
            return result;
        }

        protected abstract IAsyncResult BeginQueryCore(EntityQuery query, AsyncCallback callback, object userState);
        public IAsyncResult BeginSubmit(EntityChangeSet changeSet, AsyncCallback callback, object userState)
        {
            if (callback == null)
            {
                throw new ArgumentNullException("callback");
            }
            if (changeSet == null)
            {
                throw new ArgumentNullException("changeSet");
            }
            if (changeSet.IsEmpty)
            {
                throw new InvalidOperationException(Resource.DomainClient_EmptyChangeSet);
            }
            DomainClientAsyncResult result = DomainClientAsyncResult.CreateSubmitResult(this, changeSet, callback, userState);
            result.InnerAsyncResult = this.BeginSubmitCore(changeSet, delegate (IAsyncResult result) {
                DomainClientAsyncResult asyncState = (DomainClientAsyncResult) result.AsyncState;
                asyncState.InnerAsyncResult = result;
                asyncState.Complete();
            }, result);
            return result;
        }

        protected virtual IAsyncResult BeginSubmitCore(EntityChangeSet changeSet, AsyncCallback callback, object userState)
        {
            throw new NotSupportedException();
        }

        public void CancelInvoke(IAsyncResult asyncResult)
        {
            this.VerifyCancellationSupport();
            DomainClientAsyncResult result = this.EndAsyncResult(asyncResult, AsyncOperationType.Invoke, true);
            this.CancelInvokeCore(result.InnerAsyncResult);
        }

        protected virtual void CancelInvokeCore(IAsyncResult asyncResult)
        {
        }

        public void CancelQuery(IAsyncResult asyncResult)
        {
            this.VerifyCancellationSupport();
            DomainClientAsyncResult result = this.EndAsyncResult(asyncResult, AsyncOperationType.Query, true);
            this.CancelQueryCore(result.InnerAsyncResult);
        }

        protected virtual void CancelQueryCore(IAsyncResult asyncResult)
        {
        }

        public void CancelSubmit(IAsyncResult asyncResult)
        {
            this.VerifyCancellationSupport();
            DomainClientAsyncResult result = this.EndAsyncResult(asyncResult, AsyncOperationType.Submit, true);
            this.CancelSubmitCore(result.InnerAsyncResult);
        }

        protected virtual void CancelSubmitCore(IAsyncResult asyncResult)
        {
        }

        private DomainClientAsyncResult EndAsyncResult(IAsyncResult asyncResult, AsyncOperationType operationType, bool cancel)
        {
            DomainClientAsyncResult result = asyncResult as DomainClientAsyncResult;
            if ((result != null) && (!object.ReferenceEquals(this, result.DomainClient) || (result.AsyncOperationType != operationType)))
            {
                throw new ArgumentException(Resources.WrongAsyncResult, "asyncResult");
            }
            return AsyncResultBase.EndAsyncOperation<DomainClientAsyncResult>(asyncResult, cancel);
        }

        public InvokeCompletedResult EndInvoke(IAsyncResult asyncResult)
        {
            DomainClientAsyncResult result = this.EndAsyncResult(asyncResult, AsyncOperationType.Invoke, false);
            return this.EndInvokeCore(result.InnerAsyncResult);
        }

        protected abstract InvokeCompletedResult EndInvokeCore(IAsyncResult asyncResult);
        public QueryCompletedResult EndQuery(IAsyncResult asyncResult)
        {
            DomainClientAsyncResult result = this.EndAsyncResult(asyncResult, AsyncOperationType.Query, false);
            return this.EndQueryCore(result.InnerAsyncResult);
        }

        protected abstract QueryCompletedResult EndQueryCore(IAsyncResult asyncResult);
        public SubmitCompletedResult EndSubmit(IAsyncResult asyncResult)
        {
            DomainClientAsyncResult result = this.EndAsyncResult(asyncResult, AsyncOperationType.Submit, false);
            SubmitCompletedResult result2 = this.EndSubmitCore(result.InnerAsyncResult);
            Dictionary<int, Entity> dictionary = Enumerable.ToDictionary<ChangeSetEntry, int, Entity>(result.EntityChangeSet.GetChangeSetEntries(), (Func<ChangeSetEntry, int>) (p => p.Id), (Func<ChangeSetEntry, Entity>) (p => p.Entity));
            foreach (ChangeSetEntry entry in result2.Results)
            {
                entry.ClientEntity = dictionary[entry.Id];
            }
            return result2;
        }

        protected abstract SubmitCompletedResult EndSubmitCore(IAsyncResult asyncResult);
        private void VerifyCancellationSupport()
        {
            if (!this.SupportsCancellation)
            {
                throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Resource.DomainClient_CancellationNotSupported, new object[] { base.GetType().FullName }));
            }
        }

        public IEnumerable<Type> EntityTypes
        {
            get
            {
                return this._entityTypes;
            }
            set
            {
                if (this._entityTypes != null)
                {
                    throw new InvalidOperationException(Resource.DomainClient_EntityTypesAlreadyInitialized);
                }
                this._entityTypes = value.ToList<Type>().AsReadOnly();
            }
        }

        public virtual bool SupportsCancellation
        {
            get
            {
                return false;
            }
        }
    }
}

